package com.by.course.serivce.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.by.course.entity.base.BaseResult;
import com.by.course.entity.bo.*;
import com.by.course.entity.vo.appointment.req.AddBaseAppointmentVO;
import com.by.course.entity.vo.appointment.req.GetBaseAppointmentVO;
import com.by.course.entity.vo.appointment.req.UpdateBaseAppointmentVO;
import com.by.course.entity.vo.appointment.resp.BaseAppointmentResultVO;
import com.by.course.enums.CommonStatusEnum;
import com.by.course.enums.ErrEnum;
import com.by.course.execption.BusinessException;
import com.by.course.mapper.BaseAppointmentMapper;
import com.by.course.mapper.BaseLessonMapper;
import com.by.course.mapper.BaseScheduleMapper;
import com.by.course.mapper.BaseUserBindMapper;
import com.by.course.serivce.BaseAppointmentService;
import com.by.course.serivce.BaseCourseService;
import com.by.course.serivce.BaseLessonService;
import com.by.course.serivce.BaseScheduleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;


@Service
public class BaseAppointmentServiceImpl extends ServiceImpl<BaseAppointmentMapper, BaseAppointment> implements BaseAppointmentService {

    @Resource
    private BaseAppointmentMapper baseAppointmentMapper;

    @Resource
    private BaseAppointmentService baseAppointmentService;

    @Resource
    private BaseScheduleMapper baseScheduleMapper;

    @Resource
    private BaseScheduleService baseScheduleService;

    private final ReentrantLock lock = new ReentrantLock();

    @Resource
    private BaseLessonMapper baseLessonMapper;

    @Autowired
    private BaseLessonService baseLessonService;

    @Resource
    private BaseCourseService baseCourseService;

    @Resource
    private BaseUserBindMapper baseUserBindMapper;

    @Override
    public BaseResult<String> createAppointment(AddBaseAppointmentVO vo) {
        lock.lock();
        try {
            Long scheduleId = vo.getScheduleId();
            BaseSchedule baseSchedule = baseScheduleMapper.selectById(scheduleId);
            if (baseSchedule == null) {
                throw new BusinessException("课程不存在", ErrEnum.APPOINTMENT_ERR.getCode());
            }

            BaseAppointment exists = baseAppointmentMapper.selectAppointmentByUserIdAndScheduleId(scheduleId, vo.getUserId());
            if (exists == null) {
                if (baseSchedule.getMaxStudents() <= 0) {
                    throw new BusinessException("课程已满", ErrEnum.APPOINTMENT_ERR.getCode());
                }
                List<BaseAppointment> baseAppointmentList = baseAppointmentMapper.selectAppointmentByScheduleId(scheduleId);
                long count = baseAppointmentList.stream().filter(t -> t.getStatus().equals(CommonStatusEnum.NORMAL.getCode())).count();
                if (count >= baseSchedule.getMaxStudents()) {
                    throw new BusinessException("课程已满", ErrEnum.APPOINTMENT_ERR.getCode());
                }
                BaseAppointment baseAppointment = new BaseAppointment();
                baseAppointment.setScheduleId(vo.getScheduleId());
                baseAppointment.setUserId(vo.getUserId());
                baseAppointment.setStatus(vo.getStatus());
                baseAppointmentService.save(baseAppointment);
                return BaseResult.builder().build();
            }

            exists.setStatus(vo.getStatus());
            baseAppointmentMapper.updateByPrimaryKeySelective(exists);
        } finally {
            lock.unlock();
        }
        return BaseResult.builder().build();
    }

    @Override
    public BaseResult<List<BaseAppointmentResultVO>> getAppointmentByUserId(GetBaseAppointmentVO vo) {
        List<BaseAppointment> baseAppointmentList = baseAppointmentMapper.selectAppointmentByUserId(vo.getUserId());
        if (baseAppointmentList == null || baseAppointmentList.isEmpty()) {
            return new BaseResult.Builder<List<BaseAppointmentResultVO>>().setData(null).build();
        }
        if (vo.getStatus() != null) {
            baseAppointmentList = baseAppointmentList.stream()
                    .filter(t -> t.getStatus().equals(vo.getStatus()))
                    .collect(Collectors.toList());
        }

        if (baseAppointmentList.isEmpty()) {
            return new BaseResult.Builder<List<BaseAppointmentResultVO>>().setData(null).build();
        }

        List<Long> scheduleIdList = baseAppointmentList.stream().map(BaseAppointment::getScheduleId).collect(Collectors.toList());
        List<BaseSchedule> baseScheduleList = baseScheduleService.listByIds(scheduleIdList);

        if (CollectionUtil.isEmpty(baseScheduleList)) {
            return new BaseResult.Builder<List<BaseAppointmentResultVO>>().setData(null).build();
        }

        List<Long> lessonIdList = baseScheduleList.stream().map(BaseSchedule::getLessonId).collect(Collectors.toList());
        List<BaseLesson> baseLessonList = baseLessonService.listByIds(lessonIdList);
        if (CollectionUtil.isEmpty(baseLessonList)) {
            return new BaseResult.Builder<List<BaseAppointmentResultVO>>().setData(null).build();
        }

        List<Long> courseIdList = baseLessonList.stream().map(BaseLesson::getCourseId).collect(Collectors.toList());
        List<BaseCourse> baseCourseList = baseCourseService.listByIds(courseIdList);
        if (CollectionUtil.isEmpty(baseCourseList)) {
            return new BaseResult.Builder<List<BaseAppointmentResultVO>>().setData(null).build();
        }

        Map<Long, BaseCourse> baseCourseMap = baseCourseList.stream()
                .collect(Collectors.toMap(BaseCourse::getId, t -> t));

        Map<Long, BaseLesson> baseLessonMap = baseLessonList.stream()
                .collect(Collectors.toMap(BaseLesson::getId, t -> t));

        Map<Long, BaseSchedule> baseScheduleMap = baseScheduleList.stream()
                // .filter(t -> t.getStartTime().isAfter(vo.getStartTime()) && t.getEndTime().isBefore(vo.getEndTime()))
                .collect(Collectors.toMap(BaseSchedule::getId, t -> t));

        List<BaseAppointmentResultVO> baseAppointmentResultVoList = baseAppointmentList.stream().map(t -> {
            BaseAppointmentResultVO baseAppointmentResultVO = new BaseAppointmentResultVO();
            BeanUtil.copyProperties(t, baseAppointmentResultVO);
            BaseSchedule baseSchedule = baseScheduleMap.get(t.getScheduleId());
            BaseLesson baseLesson = baseLessonMap.get(baseSchedule.getLessonId());
            baseAppointmentResultVO.setLessonTitle(baseLesson.getTitle().trim());
            BaseCourse baseCourse = baseCourseMap.get(baseLesson.getCourseId());
            baseAppointmentResultVO.setCourseName(baseCourse.getName().trim());
            baseAppointmentResultVO.setStartTime(baseSchedule.getStartTime());
            baseAppointmentResultVO.setEndTime(baseSchedule.getEndTime());
            return baseAppointmentResultVO;
        }).collect(Collectors.toList());

        return new BaseResult.Builder<List<BaseAppointmentResultVO>>().setData(baseAppointmentResultVoList).build();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public BaseResult<String> updateAppointment(List<UpdateBaseAppointmentVO> vo) {
        List<BaseAppointment> baseAppointmentList = baseAppointmentMapper.selectBatchIds(vo.stream().map(UpdateBaseAppointmentVO::getId).collect(Collectors.toList()));
        Map<Long, Integer> statusMap = vo.stream().collect(Collectors.toMap(UpdateBaseAppointmentVO::getId, UpdateBaseAppointmentVO::getStatus));
        for (BaseAppointment baseAppointment : baseAppointmentList) {
            Integer status = statusMap.get(baseAppointment.getId());
            if (status == null) {
                throw new BusinessException("修改状态错误", ErrEnum.APPOINTMENT_ERR.getCode());
            }
            if (!baseAppointment.getStatus().equals(CommonStatusEnum.NORMAL.getCode())) {
                throw new BusinessException("状态错误", ErrEnum.APPOINTMENT_ERR.getCode());
            }
            BaseSchedule baseSchedule = baseScheduleMapper.selectById(baseAppointment.getScheduleId());
            BaseUserBind baseUserBind = baseUserBindMapper.selectPeriod(baseSchedule.getTeacherId(), baseAppointment.getUserId());
            if (baseUserBind.getPeriod() <= 0) {
                throw new BusinessException("没有可用课时", ErrEnum.APPOINTMENT_ERR.getCode());
            }
            baseUserBind.setPeriod(baseUserBind.getPeriod() - 1);
            baseUserBindMapper.updateById(baseUserBind);
            baseAppointmentMapper.updateStatus(baseAppointment.getId(), status);
        }
        return BaseResult.builder().build();
    }
}
